package chapter_03.usestack;

import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

/**
 * 中缀表达式转后缀表达式
 * https://blog.csdn.net/walkerkalr/article/details/22798365
 */
public class InfixToSufix {
    private Stack<String> operator;

    public InfixToSufix() {
        this.operator = new Stack<>();
    }

    public String convert(String calCuteStr) {
        //定义优先级
        HashMap<String, Integer> calLevel = new HashMap<>();
        calLevel.put("*", 1);
        calLevel.put("/", 1);
        calLevel.put("+", 2);
        calLevel.put("-", 2);

        List<String> calculator = Arrays.asList("+", "-", "*", "/", "(", ")");

        calCuteStr = calCuteStr.replace(" ", "");
        LinkedList<Object> input = new LinkedList<>();

        int start = 0;
        String temp = "";
        for(int i = 0; i < calCuteStr.length(); i++) {
            if(Character.isDigit(calCuteStr.charAt(i))) {
                temp += calCuteStr.charAt(i);
            } else if (i < calCuteStr.length() - 1) {
                if(temp != "") {
                    input.add(temp);
                }
                temp = "";
                input.add(calCuteStr.charAt(i) + "");
            }
            if (i == (calCuteStr.length() - 1)) {
                if(temp != "") {
                    input.add(temp);
                }
            }
        }

        StringBuilder resBuffer = new StringBuilder();
        for (Object o : input) {
            if(")".equals(o.toString())) {
                while(!operator.isEmpty()) {
                    String popValue = operator.pop();
                    if(!popValue.equals("(")) {
                        resBuffer.append(popValue);
                    }
                    if("(".equals(popValue)) {
                        break;
                    }
                }
            } else if (!calculator.contains(o)) {
                resBuffer.append(o);
            } else {
                if (operator.isEmpty() || "(".equals(o.toString()) || "(".equals(operator.peek()) || calLevel.get(o) <= calLevel.get(operator.peek())){
                    operator.add(o.toString());
                } else {
                    while(!operator.isEmpty()) {
                        String popValue = operator.pop();
                        String peekValue = operator.peek();

                        if(!popValue.equals("(")) {
                            resBuffer.append(popValue);
                        }

                        if(peekValue == null || calLevel.get(peekValue) > calLevel.get(popValue)) {
                            break;
                        }
                    }

                }
            }
        }

        if(!operator.isEmpty()) {
            resBuffer.append(operator.pop());
        }
        return resBuffer.toString();
    }
}
